package interpreter

import (
	"parse/src/token"
	"parse/src/utils"
	"strconv"
)

// 错误
type Error struct {
	PosStart  *token.Position // 错误的开始位置
	PosEnd    *token.Position // 错误的结束位置
	ErrorName string          // 错误名称
	Details   string          // 错误详情
}

func NewError(posStart *token.Position, posEnd *token.Position, errorName string, details string) *Error {
	err_ := &Error{
		PosStart:  posStart,
		PosEnd:    posEnd,
		ErrorName: errorName,
		Details:   details,
	}
	return err_
}

// 简化版的错误实例化
func NewErrorEasy(t *token.Token, errorName string, details string) *Error {
	err_ := &Error{
		PosStart:  t.PosStart,
		PosEnd:    t.PosEnd,
		ErrorName: errorName,
		Details:   details,
	}
	return err_
}

// 简化版的错误实例化
func NewIllegalError(t *token.Token, details string) *Error {
	err_ := &Error{
		PosStart:  t.PosStart,
		PosEnd:    t.PosEnd,
		ErrorName: "语法错误",
		Details:   details,
	}
	return err_
}

// 完成了
func NewFinishedError(t *token.Token, details string) *Error {
	err_ := &Error{
		PosStart:  t.PosStart,
		PosEnd:    t.PosEnd,
		ErrorName: "done",
		Details:   details,
	}
	return err_
}

// 转化为错误字符串
func (e *Error) ToString() string {
	result_ := "错误名称：" + e.ErrorName + "\n"
	result_ += "错误详情：" + e.Details + "\n"
	result_ += "错误文件：" + e.PosStart.Fn + "，行数：" + strconv.Itoa(e.PosEnd.Ln+1) + "；列数：" + strconv.Itoa(e.PosEnd.Col) + "\n"
	result_ += "\n" + utils.StringWithArrows(e.PosStart.FText, e.PosStart, e.PosEnd)
	return result_
}

// 运行时错误
type RTError struct {
	*Error
	Context *Context
}

// 运行时错误
func NewRTError(posStart *token.Position, posEnd *token.Position, detail string, ctx *Context) *RTError {
	res := &RTError{
		Error: &Error{
			PosStart:  posStart,
			PosEnd:    posEnd,
			ErrorName: "运行时错误",
			Details:   detail,
		},
		Context: ctx,
	}
	return res
}

// 转化为错误字符串
func (e *RTError) ToString() string {
	result_ := e.GenerateTraceBack()
	result_ += "错误名称：" + e.ErrorName + "\n"
	result_ += "错误详情：" + e.Details + "\n"
	result_ += "错误文件：" + e.PosStart.Fn + "，行数：" + string(e.PosEnd.Ln+1) + "；列数：" + strconv.Itoa(e.PosEnd.Col) + "\n"
	result_ += "\n" + utils.StringWithArrows(e.PosStart.FText, e.PosStart, e.PosEnd)
	return result_
}

// 产生记录
func (e *RTError) GenerateTraceBack() string {
	result_ := ""
	pos := e.PosStart
	ctx := e.Context

	for ctx != nil {
		result_ = "文件：" + pos.Fn + "，行数：" + string(pos.Ln+1) + "；列数：" + strconv.Itoa(e.PosEnd.Col) + "，在 " + ctx.DisplayName + "\n" + result_
		pos = ctx.ParentEntryPos
		ctx = ctx.Parent
	}

	return "跟踪记录（最有可能最近调用的）：" + result_
}
